package com.pn.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

import java.security.KeyPair;

/*
  授权服务器的配置类:
 */
@Configuration
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    /*
      1.指定生成的token的存储位置 --- 配置TokenStore的bean对象来指定：
        配置TokenStore接口的实现类JwtTokenStore的bean对象就表示将生成jwt token;
     */

    //配置jwt token的转换器
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter(){
        //创建jwt token转换器 --一般都是new无参构造器
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        /*
          给jwt token转换器设置私钥:
         */
        //读取类路径资源(文件) -- 将类路径资源(文件)封装到类路径资源对象中
        ClassPathResource resource = new ClassPathResource("mmy-jwt.jks");
        //创建钥匙工厂 -- 参数一是读取了类路径下的密钥文件的资源对象,参数二是密钥的密码
        KeyStoreKeyFactory keyFactory = new KeyStoreKeyFactory(resource, "mmy123".toCharArray());
        //获取密钥 -- 参数是生成密钥用的别名,返回值KeyPair对象就代表密码
        KeyPair keyPair = keyFactory.getKeyPair("mmy-jwt");
        jwtAccessTokenConverter.setKeyPair(keyPair);

        //返回jwt token转换器
        return jwtAccessTokenConverter;
    }

    @Bean
    public TokenStore tokenStore(){
        return new JwtTokenStore(jwtAccessTokenConverter());
    }


    /*
      2.配置第三方信息:
        重写void | configure(ClientDetailsServiceConfigurer clients)
     */

    //配置加密器
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                //前后台系统的前端作为第三方的信息
                .withClient("web")
                .secret(passwordEncoder().encode("web-secret"))
                .scopes("all")
                .accessTokenValiditySeconds(3600*8)//token的过期时间是8小时
                .authorizedGrantTypes("password")//指定第三方的授权模式 -- 密码模式
                .redirectUris("https://www.baidu.com")

                .and()

                //服务调用之间生成传递的token的 -- 为了安全服务之间调用也需要传递token,就使用该第三方生成token
                .withClient("service")
                .secret(passwordEncoder().encode("service-secret"))
                .scopes("all")
                .accessTokenValiditySeconds(Integer.MAX_VALUE)//token的过期时间是最大整数值,即表示永不过期
                .authorizedGrantTypes("client_credentials")//指定第三方的授权模式 -- 客户端模式(不需要登录)
                .redirectUris("https://www.baidu.com");
    }

    /*
      3.向授权服务暴露资源:
        重写void | configure(AuthorizationServerEndpointsConfigurer endpoints)
     */

    //注入认证管理器
    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        //暴露TokenStore的bean对象 -- 告诉授权服务生成的token往哪存
        endpoints.tokenStore(tokenStore());
        //暴露认证管理器 -- 实现隐式登录
        endpoints.authenticationManager(authenticationManager);
        //暴露jwt token转换器
        endpoints.accessTokenConverter(jwtAccessTokenConverter());
    }
}
